/*
   请求模块
 */
import axios from 'axios'
import JSONbig from 'json-bigint'
import store from '../store/index.js'
import { Toast } from 'vant'
import router from '../router'

/*
 刷新 Token 实例
 实例化一个新的实例，避免使用 request 引起冲突
 */
const refreshTokenReq = axios.create({
  baseURL: ''
})

/*
  本项目实例
 */
const request = axios.create({
  // 基础路径
  baseURL: '',
  // 修改响应数据
  transformResponse: [function (data) {
    try {
      // 如果转换成功，则直接把结果返回
      return JSONbig.parse(data)
    } catch (e) {
      // console.log('转换失败', err)
      return data
    }
  }]
})

// 请求拦截
request.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  const { user } = store.state
  if (user) {
    config.headers.Authorization = `Bearer ${user.token}`
  }
  // 处理完之后一定要把 config 返回，否则请求就会停在这里
  return config
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})
// 响应拦截
request.interceptors.response.use(function (response) {
  // 响应成功进入这里
  return response
}, async function (error) {
  // 请求失败进入这里
  // console.log(error)
  const status = error.response.status
  if (status === 400) {
    Toast.fail('客户端请求参数异常！')
  } else if (status === 401) {
    // token 无效
    const { user } = store.state
    if (!user || !user.token) {
      // 直接跳转到登录页
      return redirectLogin()
    }
    // 使用 refresh_token 请求获取新的 token
    try {
      const { data: { data: { token: res } } } = await refreshTokenReq({
        method: 'PUT',
        url: '/app/v1_0/authorizations',
        headers: {
          Authorization: `Bearer ${user.refresh_token}`
        }
      })
      user.token = res
      store.commit('setUser', user)
      // 把失败的请求重新发出去
      // error.config 是本次请求的相关配置信息对象
      // 这里使用 request 发请求，它会走自己的拦截器
      // 它的请求拦截器中通过 store 容器访问 token 数据
      /*
        这个过程会产生三个请求
        1. 请求获取响应失败
        2. 重新获取 token
        3. 携新获取的 token 信息，重新发送请求获取响应
       */
      return request(error.config)
    } catch (e) {
      redirectLogin() // 刷新 token 失败，重新登陆
    }
  } else if (status === 403) {
    Toast.fail('没有操作权限！')
  } else if (status >= 500) {
    Toast.fail('服务端异常，请稍后重试')
  }
  // 抛出异常
  return Promise.reject(error)
})

function redirectLogin () {
  // router.replace('./login')
  // 跟 router.push 很像，唯一的不同就是，它不会向 history 添加新记录
  router.replace({
    name: 'login',
    // 传递查询参数，查询参数会以 ？ 作为分隔符放到 url 后面
    query: {
      // 参数名可自定义
      // router.currentRoute 和我们在组件中获取的 this.$route 是一个东西
      returnUrl: router.currentRoute.fullPath
    }
  })
}

export default request
